package com.copsoftware.utils.dao;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.util.StringUtils;

import com.copsoftware.support.annotations.Like;
import com.copsoftware.utils.beans.ObjectConverter;

public class WhereBuilder {

	Object bean;

	protected BeanWrapper target;

	private Map dispatchAttribute;

	private String alias;

	List columns = new ArrayList();

	public WhereBuilder(Object bean) {
		this.bean = bean;
		target = new BeanWrapperImpl(bean);
		dispatchAttribute = new HashMap();
	}

	public WhereBuilder(String alias, Object bean) {
		this.alias = alias;
		this.bean = bean;
		target = new BeanWrapperImpl(bean);
		dispatchAttribute = new HashMap();
	}

	public void execute() {

		Object[] fields = bean.getClass().getDeclaredFields();
		for (int i = 0; i < fields.length; i++) {
			String fieldName = ((Field) (fields[i])).getName();
//			if (!dispatchAttribute.containsKey(fieldName)) continue;
			Object columnValue = target.getPropertyValue(fieldName);

			if (columnValue != null
					&& StringUtils.hasText(columnValue.toString())) {
				if (columnValue instanceof Number) {
					if (ObjectConverter.convertToint(columnValue) == -1)
						continue;
				}
				if (columnValue.equals("-1")) continue;
				if (dispatchAttribute.containsKey(fieldName)) 
					buildColumn((Field) (fields[i]), columnValue);
			}
		}

	}

	public void buildColumn(Field field, Object columnValue) {
		String columnName = "";
		Method method = target.getPropertyDescriptor(field.getName())
				.getReadMethod();
		if (dispatchAttribute.containsKey(field.getName())) {
			columnName = (String) dispatchAttribute.get(field.getName());
		}
		
//		else {
//			columnName = field.getName();
//		}

		boolean isLike = false;
		if (field.isAnnotationPresent(Like.class)) {
			columnValue = "%" + columnValue + "%";
			isLike = true;
		}
		columns.add(new Column(field.getName(), columnName, columnValue,
						isLike));
	}

	public StringBuffer getSql() {
		StringBuffer sql = new StringBuffer();
		boolean asignFecha = false;
		for (int i = 0; i < columns.size(); i++) {
			Column column = (Column) columns.get(i);
			String columnName = column.getColumnName();
			Object columnValue = column.getValue();
			if ((columnName.equalsIgnoreCase("feRangoInicial") || columnName
					.equalsIgnoreCase("feRangoFinal"))) {
//				if (!asignFecha) {
//					sql.append(getCustomDate());
//					i++;
//					asignFecha = true;
//				}

			} else {
				if (alias != null && alias.length() != 0) {
					columnName = alias + "." + columnName;
				}
				if (!column.isLike()) {
					sql.append(" " + columnName + " = ");
				} else {
					sql.append(" " + columnName + " LIKE ");
				}
				if (columnValue instanceof Number) {
					sql.append(columnValue);
				} else {
					sql.append("\'").append(columnValue).append("\'");
				}

			}
			if ((i + 1) < columns.size()) {
				sql.append(" AND ");
			}
		}
		return sql;
	}

	public StringBuffer getSqlWithArgs() {
		StringBuffer sql = new StringBuffer();
		boolean asignFecha = false;
		for (int i = 0; i < columns.size(); i++) {
			Column column = (Column) columns.get(i);
			String columnName = column.getColumnName();
			if ((columnName.equalsIgnoreCase("feRangoInicial") || columnName
					.equalsIgnoreCase("feRangoFinal"))) {
//				if (!asignFecha) {
//					i++;
//					sql.append(getCustomDate());
//					asignFecha = true;
//				}

			} else {
				if (alias != null && alias.length() != 0) {
					columnName = alias + "." + columnName;
				}
				if (!column.isLike()) {
					sql.append(" " + columnName + " = ? ");
				} else {
					sql.append(" " + columnName + " LIKE ? ");
				}

			}
			if ((i + 1) < columns.size()) {
				sql.append(" AND ");
			}
		}
		return sql;
	}

	public Object[] getParameters() {
		List parameters = new ArrayList();
		for (Iterator iterator = columns.iterator(); iterator.hasNext();) {
			Column column = (Column) iterator.next();
			String columnName = column.getColumnName();
			if ((columnName.equalsIgnoreCase("feRangoInicial") || columnName
					.equalsIgnoreCase("feRangoFinal"))) {
				continue;
			}
			parameters.add(column.getValue());
		}
		return parameters.isEmpty() ? null : parameters.toArray();
	}

	public void registerMatch(String fieldNameFlt, String fieldNameSQLHQL) {
		dispatchAttribute.put(fieldNameFlt, fieldNameSQLHQL);
	}

//	public void registerColumnFecha(String attribute) {
//		dispatchAttribute.put("fecha", attribute);
//	}

//	private StringBuffer getCustomDate() {
//		StringBuffer sql = new StringBuffer();
//		if (columns.indexOf(new Column("feRangoInicial")) != -1
//				&& columns.indexOf(new Column("feRangoFinal")) != -1) {
//			Date fechaInicial = (Date) ((Column) columns.get(columns
//					.indexOf(new Column("feRangoInicial")))).getValue();
//			Date fechaFinal = (Date) ((Column) columns.get(columns
//					.indexOf(new Column("feRangoFinal")))).getValue();
//			String columnName = (String) dispatchAttribute.get("fecha");
//			if (alias != null && alias.length() != 0) {
//				columnName = alias + "." + columnName;
//			}
//			RPUtilsCommons.agregarFechaRangoFiltro(sql, columnName,
//					fechaInicial, fechaFinal);
//		}
//		// sql.append(" AND ");
//
//		return sql;
//
//	}

	class Column {
		private Object value;

		private String columnName;

		private String fieldName;

		private boolean like;

		public Column(String fieldName) {
			this.fieldName = fieldName;
		}

		public Column(String fieldName, String columnName, Object value,
				boolean like) {
			this.fieldName = fieldName;
			this.value = value;
			this.columnName = columnName;
			this.like = like;
		}

		public Object getValue() {
			return value;
		}

		public void setValue(Object value) {
			this.value = value;
		}

		public String getColumnName() {
			return columnName;
		}

		public void setColumnName(String columnName) {
			this.columnName = columnName;
		}

		public String getFieldName() {
			return fieldName;
		}

		public void setFieldName(String fieldName) {
			this.fieldName = fieldName;
		}

		public boolean isLike() {
			return like;
		}

		public void setLike(boolean like) {
			this.like = like;
		}

		public boolean equals(Object o) {
			if (this == o)
				return true;
			if (o == null || getClass() != o.getClass())
				return false;

			Column column = (Column) o;

			if (!fieldName.equals(column.fieldName))
				return false;

			return true;
		}

		public int hashCode() {
			return fieldName.hashCode();
		}
	}
}
